package org.apache.ocean.main.search;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;

import org.apache.ocean.main.Index.IndexSnapshot;
import org.apache.ocean.main.fields.DateFieldType;
import org.apache.ocean.main.search.Search.FacetDateQuery;
import org.apache.ocean.main.search.Search.FacetDateResult;
import org.apache.ocean.main.search.Search.FacetResult;
import org.apache.ocean.main.search.Search.FacetValue;
import org.apache.ocean.main.search.cache.DocSetFacetCacheKey;
import org.apache.ocean.main.search.cache.QueryDocSetCacheKey;
import org.apache.ocean.main.search.cache.RangeDocSetCacheKey;
import org.apache.ocean.main.util.DateMathParser;
import org.apache.ocean.main.util.Range;

import com.ibm.icu.util.ULocale;

public class IndexFacetDateSearch implements Callable<FacetResult> {
	private final FacetDateQuery facetDateQuery;
	private final IndexSnapshot indexSnapshot;
	private final QueryDocSetCacheKey queryDocSetCacheKey;

	public IndexFacetDateSearch(FacetDateQuery facetDateQuery, QueryDocSetCacheKey queryDocSetCacheKey, IndexSnapshot indexSnapshot) {
		this.facetDateQuery = facetDateQuery;
		this.queryDocSetCacheKey = queryDocSetCacheKey;
		this.indexSnapshot = indexSnapshot;
	}
  
	public FacetResult call() throws Exception {
		List<FacetValue> facetValues = new LinkedList<FacetValue>();
		Date now = new Date();
		DateFieldType dateFieldType = (DateFieldType) indexSnapshot.getIndexSchemaCategory().getField(facetDateQuery.getField()).getFieldType();
		Date startDate = dateFieldType.parseMath(now, facetDateQuery.getStart());
		Date endDate = dateFieldType.parseMath(now, facetDateQuery.getEnd());
		final DateMathParser gapDateMathParser = new DateMathParser(dateFieldType.UTC, ULocale.US);
		gapDateMathParser.setNow(now);
		Date low = startDate;
		while (low.before(endDate)) {
			gapDateMathParser.setNow(low);
			String name = dateFieldType.objectToExternal(low);
			Date high = gapDateMathParser.parseMath(facetDateQuery.getGap());
			if (endDate.before(high)) {
				if (facetDateQuery.isHardEnd()) {
					high = endDate;
				} else {
					endDate = high;
				}
			}
			if (high.before(low)) {
				throw new Exception("date facet infinite loop (is gap negative?)");
			}
			Range range = new Range(low, true, high, true);
			RangeDocSetCacheKey rangeDocSetCacheKey = new RangeDocSetCacheKey(facetDateQuery.getField(), range);
			DocSetFacetCacheKey docSetFacetCacheKey = new DocSetFacetCacheKey(rangeDocSetCacheKey, queryDocSetCacheKey);
			int count = indexSnapshot.getFacetValue(docSetFacetCacheKey);
			facetValues.add(new FacetValue(name, count));
			low = high;
		}
		return new FacetDateResult(facetValues, now, facetDateQuery.getGap());
	}
}
